/**************************************************************************************
*
*	Copyright (C) 2010 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	VertexDeclaration.cpp
*
*	Comments	-	See VertexDeclaration.h
*
**************************************************************************************/

#ifdef __PSX_WINDOWS_WINDOW

#include "../Include/VertexDeclaration.h"
#include "../Include/Renderer.h"
#include "../Include/DX9Mapping.h"

namespace Pulse
{

	VertexDeclaration::VertexDeclaration( void )
		: m_pVertexDecl( NULL )
	{

	}

	VertexDeclaration::~VertexDeclaration( void )
	{
		Cleanup();
	}

	BOOL VertexDeclaration::CreateResource( void )
	{
		if ( IsResourceCreated() )
		{
			PSX_PushWarning( "Resource has already been created." );
			return FALSE;
		}

		//Initialize();
		SetFlagCreated();
		return TRUE;
	}

	BOOL VertexDeclaration::DestroyResource( void )
	{
		if ( IsResourceCreated() )
		{
			DisableResource();
			Cleanup();
			SetFlagUnloaded();
			SetFlagDestroyed();
		}

		return TRUE;
	}

	BOOL VertexDeclaration::DisableResource( void )
	{
		if ( !IsResourceCreated() )
		{
			PSX_PushWarning( "Resource has not been created." );
			return FALSE;
		}

		SetFlagDisabled();
		return TRUE;
	}

	BOOL VertexDeclaration::RestoreResource( void )
	{
		if ( !IsResourceCreated() )
		{
			PSX_PushWarning( "Resource has not been created." );
			return FALSE;
		}

		SetFlagRestored();
		return TRUE;
	}

	BOOL VertexDeclaration::LoadResource( const CHAR *pFilename )
	{
		return TRUE;
	}

	BOOL VertexDeclaration::SaveResource( const CHAR *pFilename )
	{
		return TRUE;
	}

	EErrorCode::Type VertexDeclaration::Initialize( void )
	{
		Cleanup();

		IDirect3DDevice9 *pDevice = (IDirect3DDevice9*)Renderer::GetInstance()->GetDevice()->GetDevice();

		SIZE_T numElements = GetElementCount();

		D3DVERTEXELEMENT9 *pElements = new D3DVERTEXELEMENT9[numElements + 1];

		for ( UINT i = 0; i < numElements; ++i )
			pElements[i] = DX9Mapping::ToVertexElement( &m_elements[i] );

		// Add dummy element at the end
		D3DVERTEXELEMENT9 *pElem = &pElements[ numElements ];
		pElem->Method = 0;
		pElem->Offset = 0;
		pElem->Stream = 0xFF;
		pElem->Type = D3DDECLTYPE_UNUSED;
		pElem->Usage = 0;
		pElem->UsageIndex = 0;

		// Finally create vertex declaration
		pDevice->CreateVertexDeclaration( pElements, &m_pVertexDecl );

		delete pElements;

		return EErrorCode::NONE;
	}

	void VertexDeclaration::Cleanup( void )
	{
		PSX_SafeRelease( m_pVertexDecl );
	}

	void VertexDeclaration::AddVertexElement( const VertexElement *pElements, SIZE_T count )
	{
		for ( SIZE_T i = 0; i < count; ++i )
			m_elements.PushBack( pElements[i] );

		Initialize();
	}

	void VertexDeclaration::Bind( void )
	{
		IDirect3DDevice9 *pDevice = (IDirect3DDevice9*)Renderer::GetInstance()->GetDevice()->GetDevice();

		pDevice->SetVertexDeclaration( m_pVertexDecl );
	}

	const VertexElement * VertexDeclaration::GetVertexElement( EVertexElementUsage::Type usage, UINT index )
	{
		UINT currIndex = 0;
		SIZE_T count = m_elements.GetSize();

		for ( SIZE_T i = 0; i < count; ++i )
		{
			if ( m_elements[i].usage == usage )
			{
				if ( currIndex == index )
					return &m_elements[i];
				else
					++currIndex;
			}
		}

		return PSX_NULL;
	}

}

#endif __PSX_WINDOWS_WINDOW
